package com.m1.tzolkin.model.board;

import java.util.Map;

import com.m1.tzolkin.model.IAction;
import com.m1.tzolkin.model.IBank;
import com.m1.tzolkin.model.ITZCalendar;
import com.m1.tzolkin.model.ObservableModel;
import com.m1.tzolkin.model.exceptions.EndOfGameException;
import com.m1.tzolkin.model.exceptions.IllegalWorkerOperationException;
import com.m1.tzolkin.model.exceptions.NoMovedWorkersException;
import com.m1.tzolkin.model.exceptions.NoPlaceException;
import com.m1.tzolkin.model.exceptions.NoWorkerHereException;
import com.m1.tzolkin.model.exceptions.NotEnoughCornException;
import com.m1.tzolkin.model.exceptions.NotEnoughWorkersException;
import com.m1.tzolkin.model.exceptions.WaitingOperationsException;
import com.m1.tzolkin.model.log.ILog;
import com.m1.tzolkin.model.players.ITZPlayer;
import com.m1.tzolkin.model.players.IWorker;
import com.m1.tzolkin.model.util.board.ITimedBoard;
import com.m1.tzolkin.model.wheels.IWheel;
import com.m1.tzolkin.model.wheels.WheelEnum;

/**
 * Un plateau de jeu r�gi par un calendrier de Tzolk'in avec des joueurs.
 * Un plateau est d�fini notamment par ses roues.
 *  
 * @inv <pre>
 *     getRemovedWorkers() == 0 || getPlacedWorkers() == 0
 *     getBank() != null </pre>
 * 
 */
public interface IBasicBoard extends ITimedBoard<ITZPlayer, ITZCalendar>, ITZCalendar, ObservableModel {

	// REQUETES
	
	/**
	 * Retourne le log associ� � ce plateau.
	 */
	ILog getLog();
	
	/**
	 * Retourne la roue de type t de ce plateau de jeu.
	 * @pre <pre>
	 *     t != null </pre>
	 */
	IWheel getWheel(WheelEnum t);
	
	/**
	 * Retourne la banque de ce plateau.
	 */
	IBank getBank();
	
	/**
	 * Retourne l'ouvrier sur la case Premier joueur.
	 * Retourne null si personne n'y est.
	 */
	IWorker getFirstWorker();
	
	/**
	 * Retourne true si on est en cours de changement de jour.
	 */
	int isWaitingForTurn();
	
	/**
	 * Retourne le nombre d'ouvriers retir�s durant ce tour.
	 */
	int getRemovedWorkers();
	
	/**
	 * Retourne le nombre d'ouvriers plac�s durant ce tour.
	 */
	int getPlacedWorkers();
	
	// COMMANDES
	
	/**
	 * Place un ouvrier du joueur courant dans la roue w et en paie le co�t en ma�s.
	 * @pre <pre>
	 *     isWaitingForTurn() == 0
	 *     getActualPlayer().getWorkersHand() > 0
	 *     getRemovedWorkers() == 0
	 *     w != null
	 *     getActualPlayer().getCorn() >= w.getMinimalPosition() + getPlacedWorkers() </pre>
	 * @post <pre>
	 *     getRemovedWorkers() == old getRemovedWorkers() + 1
	 *     getActualPlayer().getWorkersHand() == old getActualPlayer().getWorkersHand() - 1
	 *     getActualPlayer().getCorn() == old getActualPlayer().getCorn() - old (w.getMinimalPosition() + getPlacedWorkers()) </pre>
	 */
	void placeWorker(WheelEnum w) throws NoPlaceException, NotEnoughCornException, IllegalWorkerOperationException, NotEnoughWorkersException;
	
	/**
	 * Place un ouvrier du joueur courant sur la case Premier joueur.
	 * @pre <pre>
	 *     isWaitingForTurn() == 0
	 *     getFirstWorker() == null
	 *     getActualPlayer().getWorkersHand() > 0
	 *     getActualPlayer().getCorn() >= getPlacedWorkers() </pre>
	 * @post <pre>
	 *     getFirstWorker() == getActualPlayer() </pre>
	 */
	void placeFirstWorker() throws NoPlaceException, NotEnoughCornException, NotEnoughWorkersException, IllegalWorkerOperationException;
	
	/**
	 * Demande le retrait de l'ouvrier de la roue w en position i.
	 * Le joueur stocke les actions qu'il peut ex�cuter en fonction.
	 * @pre <pre>
	 *     isWaitingForTurn() == 0
	 *     getPlacedWorkers() == 0
	 *     getActualPlayer().getWorkersHand() < getActualPlayer().getWorkersTotal();
	 *     w != null
	 *     w.occupying(i) == getActualPlayer() </pre>
	 * @post <pre>
	 *     w.occupying(i) == null
	 *     getRemovedWorkers() == old getRemovedWorkers() + 1
	 *     getActualPlayer().getWorkersHand() == old getActualPlayer().getWorkersHand() + 1 </pre>
	 */
	Map<IAction, Integer> takeWorker(WheelEnum w, int position) throws IllegalWorkerOperationException, NoWorkerHereException;
	
	/**
	 * Ach�ve le tour du joueur courant.
	 * Si c'�tait le dernier joueur, retourne le joueur pr�sent sur la case PJ.
	 * @pre <pre>
	 *     isWaitingForTurn() == 0
	 *     getRemovedWorkers() != getPlacedWorkers()
	 *     hasStarted() && !isFinished() </pre>
	 */
	@Override
	ITZPlayer endTurn() throws WaitingOperationsException, EndOfGameException, NoMovedWorkersException;
	
}
